﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.UIElements;

namespace UnityView
{
    public abstract class AbsAdapterView : UIView, IAdapterViewEvent
    {
        protected AbsAdapterView(string name = "Adapter View") : this(UICanvas.GetInstance(), name)
        {
        }
        
        protected AbsAdapterView(IViewLayout view, string name = "Adapter View") : base(view, name)
        {
            ScrollRect = UIObject.AddComponent<ScrollRect>();
            ScrollRect.scrollSensitivity = 100f;
            ScrollRect.movementType = ScrollRect.MovementType.Clamped;
            ScrollRect.onValueChanged.AddListener(OnScroll);

            ContentView = new UILayout(this, "Content View");
            ContentTransform = ContentView.RectTransform;
            ContentTransform.anchoredPosition = Vector2.zero;

            ScrollRect.content = ContentTransform;
            ScrollRect.vertical = true;
            ScrollRect.horizontal = false;
            InternalBackgroundColor = Color.white;
            Mask = UIObject.AddComponent<Mask>();
            Mask.showMaskGraphic = false;

            // 创建一个空的Header和Footer
            headerView = EmptyLayout(ContentTransform, "Empty Header");
            footerView = EmptyLayout(ContentTransform, "Empty Footer");
        }

        public readonly UILayout ContentView;
        public readonly RectTransform ContentTransform;
        
        protected int ItemCount = 0;

        /// <summary>
        /// 滚动方向
        /// </summary>
        public virtual Orientation Orientation
        {
            get
            {
                return ScrollRect.vertical ? Orientation.Vertical : Orientation.Horizontal;
            }
            set
            {
                if (Orientation == value) return;
                switch (value)
                {
                    case Orientation.Horizontal:
                        ScrollRect.horizontal = true;
                        ScrollRect.vertical = false;
                        break;
                    case Orientation.Vertical:
                        ScrollRect.horizontal = false;
                        ScrollRect.vertical = true;
                        break;
                }
                UpdateVisibleItemCount();
                ContentTransform.anchoredPosition = Vector2.zero;
                Reload();
            }
        }

        /// <summary>
        /// 是否开启边界弹性
        /// </summary>
        public bool BounceEnable
        {
            set => ScrollRect.movementType = value ? ScrollRect.MovementType.Elastic : ScrollRect.MovementType.Clamped;
            get => ScrollRect.movementType == ScrollRect.MovementType.Clamped;
        }
        
        // 间隔
        public Vector2 spacing = Vector2.zero;

        public virtual Vector2 Spacing
        {
            set => spacing = value;
            get => spacing;
        }

        public readonly Mask Mask;

        protected readonly ScrollRect ScrollRect;
        
        public virtual void ScrollToTop(int index = 0)
        {
            ContentOffset = 0;
        }

        public virtual void ScrollToBottom()
        {
            ContentTransform.anchoredPosition = new Vector2(ContentSize.x - Width, ContentSize.y - Height);
        }
        
        public Vector2 ContentAnchor
        {
            get { return ContentTransform.anchoredPosition; }
        }
        
        // 获取内容区域的大小
        public Vector2 ContentSize
        {
            get => ContentTransform.sizeDelta;
            protected set => ContentTransform.sizeDelta = value;
        }

        [Animatable]
        public virtual float ContentOffset
        {
            set
            {
                // if (UIAnimation.OnAnimate())
                // {
                //     UIAnimation.Append(new ContentOffsetAction(this, ContentOffset, value));
                // }
                // else
                // {
                // }
                Vector2 offset = Orientation == Orientation.Horizontal ? new Vector2(value, 0) : new Vector2(0, value);
                ContentTransform.anchoredPosition = offset;
            }
            get
            {
                return Orientation == Orientation.Horizontal
                    ? -ContentTransform.anchoredPosition.x
                    : ContentTransform.anchoredPosition.y;
            }
        }
        
        /// <summary>
        /// ContentOffset 的取值范围，最小值为0
        /// </summary>
        public float ContentOffsetRange
        {
            get
            {
                float range = Orientation == Orientation.Horizontal
                    ? ContentTransform.sizeDelta.x - Width
                    : ContentTransform.sizeDelta.y - Height;
                if (range < 0) range = 0;
                return range;
            }
        }

        #region Header / Footer

        protected UILayout headerView;
        public virtual UILayout Header
        {
            set
            {
                if (value == null)
                {
                    value = EmptyLayout(ContentTransform, "Empty Header");
                }
                headerView.Destroy();
                headerView = value;
            }
            get => headerView;
        }

        public virtual float HeaderViewSize
        {
            get { return Orientation == Orientation.Vertical ? Header.Height : Header.Width; }
        }

        protected UILayout footerView;

        public virtual UILayout Footer
        {
            set
            {
                if (value == null)
                {
                    value = EmptyLayout(ContentTransform, "Empty Footer");
                }
                footerView.Destroy();
                footerView = value;
            }
            get => footerView;
        }

        public virtual float FooterViewSize => Orientation == Orientation.Vertical ? Footer.Height : Footer.Width;

        protected float ContentOffsetWithoutHeader => Orientation == Orientation.Vertical
            ? ContentTransform.anchoredPosition.y - headerView.Height
            : -ContentTransform.anchoredPosition.x - headerView.Width;

        #endregion

        /// <summary>
        /// 可见元素的数量，这个值将在 UpdateVisibleItemCount() 方法中更新
        /// </summary>
        public int VisibleItemCount { get; protected set; }

        public delegate void OnScrollDelegate(float min, float max);
        public OnScrollDelegate OnScrollListener { get; protected set; }

        protected int LastStartIndex = 0;

        // 当前起始元素的索引
        protected int StartIndex = 0;

        /// <summary>
        /// ScrollView滚动事件
        /// 在这个方法中完成对 StartIndex 的维护
        /// </summary>
        /// <param name="position">当前的滚动位置</param>
        protected virtual void OnScroll(Vector2 position)
        {
            StartIndex = GetStartIndex();
            if (StartIndex < 0)
            {
                StartIndex = 0;
                // return;
            }
            // 计算起始索引
            if (StartIndex == LastStartIndex)
            {
                var count = VisibleItemCount;
                UpdateVisibleItemCount();
                if (count != VisibleItemCount)
                {
                    LayoutSubviews();
                }
            }
            else
            {
                UpdateVisibleItemCount();
                LayoutSubviews();
                LastStartIndex = StartIndex;
            }

            // float length = Orientation == Orientation.Vertical ? ContentSize.y : ContentSize.x;
            // OnScrollListener?.Invoke();
        }
         
        /// <summary>
        /// 更新可见元素数量
        /// </summary>
        public abstract void UpdateVisibleItemCount();

        protected abstract int GetStartIndex();

        public abstract void LayoutSubviews();

        public abstract void Refresh();
        public abstract void RefreshToBottom();
        public abstract void Internal_Refresh();

        /// <summary>
        /// 在当前位置重载表视图的数据
        /// </summary>
        public abstract void Reload();

        public void Reload(bool reset)
        {
            if (reset) ContentOffset = 0;
            Reload();
        }

        // 计算ContentSize并进行赋值
        protected abstract Vector2 UpdateContentSize();

        public abstract void OnTouchDown(PointerEventData eventData);

        public abstract void OnClick(PointerEventData eventData);

        public abstract void OnPointer(PointerEventData eventData);
        public abstract void OnPointerEnter(PointerEventData eventData);
        public abstract void OnPointerExit(PointerEventData eventData);
    }

    public abstract class AbsAdapterView<TAdapter> : AbsAdapterView
    {
        protected AbsAdapterView(string name = "Adapter View") : this(UICanvas.GetInstance(), name)
        {
        }

        protected AbsAdapterView(IViewLayout view, string name = "Adapter View") : base(view, name)
        {
        }
        
        #region Adapter

        private TAdapter _adapter;

        public virtual TAdapter Adapter
        {
            set
            {
                if (value == null || value.Equals(_adapter)) return;
                _adapter = value;
                OnAdapterAttached(_adapter);
            }
            get => _adapter;
        }

        public abstract void OnAdapterAttached(TAdapter adapter);

        #endregion

        #region OnItemSelectedListener
        
        protected AdapterViewItemSelectEventHandler ItemSelectEventHandler;
        
        public delegate void ItemSelectedListener(TAdapter adapter, IViewLayout view, int index, int id);
        private ItemSelectedListener _onItemSelectedListener;

        public ItemSelectedListener OnItemSelectedListener
        {
            set
            {
                _onItemSelectedListener = value;
                if (ItemSelectEventHandler == null)
                {
                    ItemSelectEventHandler = UIObject.AddComponent<AdapterViewItemSelectEventHandler>();
                    ItemSelectEventHandler.AdapterView = this;
                }
            }
            get { return _onItemSelectedListener; }
        }

        public Vector2 TouchBeginPosition;

        public override void OnTouchDown(PointerEventData eventData)
        {
            TouchBeginPosition = eventData.position;
        }

        public override void OnClick(PointerEventData eventData)
        {
            if (_onItemSelectedListener == null) return;
            if ((eventData.position - TouchBeginPosition).sqrMagnitude > UIConstant.ClickThreshold) return;
            Vector2 vector2 = eventData.position;
            Vector2 origin = Origin;
            Vector2 pos = new Vector2(vector2.x - origin.x, Screen.height - vector2.y - origin.y);
            int index = GetItemIndex(UIConstant.Normalize(pos));
            if (index >= 0 && index < ItemCount)
            {
                OnItemSelectedListener(Adapter, CellCache[index]?.View, index, eventData.pointerId);
            }
            else
            {

            }
        }

        #endregion

        #region OnPointerEnterExitListener
        
        protected AdapterViewPointerEventHandler PointerEventHandler;
        public delegate void PointerEnterListener(TAdapter adapter, IViewLayout view, int index, int id);
        private PointerEnterListener _onPointerEnterListener;
        public delegate void PointerExitListener();
        private PointerExitListener _onPointerExitListener;
        public delegate void PointerEventListener(TAdapter adapter, IViewLayout view, int index, int id);
        private PointerEventListener _onPointerListener;

        public PointerEnterListener OnPointerEnterListener
        {
            set
            {
                _onPointerEnterListener = value;
                if (PointerEventHandler == null)
                {
                    PointerEventHandler = UIObject.AddComponent<AdapterViewPointerEventHandler>();
                    PointerEventHandler.AdapterView = this;
                }
            }
            get => _onPointerEnterListener;
        }

        public PointerExitListener OnPointerExitListener
        {
            set
            {
                _onPointerExitListener = value;
                if (PointerEventHandler == null)
                {
                    PointerEventHandler = UIObject.AddComponent<AdapterViewPointerEventHandler>();
                    PointerEventHandler.AdapterView = this;
                }
            }
            get => _onPointerExitListener;
        }

        public PointerEventListener OnPointerListener
        {
            set
            {
                _onPointerListener = value;
                if (PointerEventHandler == null)
                {
                    PointerEventHandler = UIObject.AddComponent<AdapterViewPointerEventHandler>();
                    PointerEventHandler.AdapterView = this;
                }
            }
            get => _onPointerListener;
        }

        public override void OnPointerEnter(PointerEventData eventData)
        {
            Vector2 vector2 = eventData.position;
            Vector2 origin = Origin;
            Vector2 pos = new Vector2(vector2.x - origin.x, Screen.height - vector2.y - origin.y);
            int index = GetItemIndex(UIConstant.Normalize(pos));
            if (index >= 0 && index < ItemCount)
            {
                _onPointerEnterListener?.Invoke(Adapter, CellCache[index]?.View, index, eventData.pointerId);
            }
        }

        public override void OnPointerExit(PointerEventData eventData)
        {
            _onPointerExitListener?.Invoke();
        }

        public override void OnPointer(PointerEventData eventData)
        {
            _onPointerListener?.Invoke(Adapter, this, 1, 2);
        }

        #endregion


        protected AdapterCellCache CellCache = new AdapterCellCache();

        /// <summary>
        /// 通过元素索引位置获取其起始布局位置
        /// </summary>
        /// <param name="index">元素索引</param>
        /// <returns>布局位置</returns>
        public abstract Vector2 GetItemPosition(int index);

        /// <summary>
        /// 返回包含此二维点的元素索引，如果没有满足的元素，返回-1
        /// </summary>
        /// <param name="vector2">二维点位置</param>
        /// <returns>元素索引，如果没有满足的元素，返回-1</returns>
        public abstract int GetItemIndex(Vector2 vector2);

        public sealed override void Refresh()
        {
            Internal_Refresh();
            LayoutSubviews();
        }

        public override void RefreshToBottom()
        {
            Internal_Refresh();
            ScrollToBottom();
            LayoutSubviews();
        }

        public override void Internal_Refresh()
        {
            UpdateContentSize();
        }
        
        public override void Reload()
        {
            ScrollRect.StopMovement();
            if (Adapter == null) return;

            UpdateContentSize();
        }
    }

    public interface IAdapterViewEvent
    {
        void OnTouchDown(PointerEventData eventData);
        void OnClick(PointerEventData eventData);
    }
    
    public class AdapterViewItemSelectEventHandler : MonoBehaviour, IPointerDownHandler, IPointerClickHandler
    {
        public AbsAdapterView AdapterView;
        public void OnPointerDown(PointerEventData eventData)
        {
            AdapterView.OnTouchDown(eventData);
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            AdapterView.OnClick(eventData);
        }
    }

    // public class AdapterViewPointerEnterEventHandler : MonoBehaviour, IPointerEnterHandler
    // {
    //     public AbsAdapterView AdapterView;
    //     public void OnPointerEnter(PointerEventData eventData)
    //     {
    //         AdapterView.OnPointerEnter(eventData);
    //     }
    // }
    //
    // public class AdapterViewPointerExitEventHandler : MonoBehaviour, IPointerExitHandler
    // {
    //     public AbsAdapterView AdapterView;
    //     public void OnPointerExit(PointerEventData eventData)
    //     {
    //         AdapterView.OnPointerExit(eventData);
    //     }
    // }

    public class AdapterViewPointerEventHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
    {
        public AbsAdapterView AdapterView;

        public void OnPointerEnter(PointerEventData eventData)
        {
            AdapterView.OnPointerEnter(eventData);
        }

        public void OnPointerExit(PointerEventData eventData)
        {
            AdapterView.OnPointerExit(eventData);
        }
    }
}
